Support JS libraries self-registering their exports with visibility attributes - #27436
Conversation
|
I think supporting something like this is a great idea but maybe we can bikeshed the design a little. How about limiting this to symbols actually defined in the JS library itself using symbol attributes. Perhaps something like: I don't love the In this scenario it would be possible to specify one of these without that other. If you specified If you specified I would hope that the information could all stay on the JS side, but if it needs to be plumbed back to python then it could then just be small |
|
I've updated this following the suggestion here for JS libraries to use the __export and __force symbol attributes:
The attributes are compile-time metadata and are not emitted. We no longer mutate or forward Coverage includes legacy modules, instance ESM, WASM_ESM_INTEGRATION, and O3/meta-DCE. |
sbc100
left a comment
There was a problem hiding this comment.
This is looking much better now! Thanks for being flexible.
sbc100
left a comment
There was a problem hiding this comment.
lgtm % comment.
Can you add a ChangeLog entry for this?
281ec85 to
bc3d67c
Compare
|
Changelog added now as well. |
|
6.0.6 is about to be released in next few minutes/hours, so maybe we hold off landing this until after that happens in order to avoid having to move the changelog entry. See emscripten-core/emsdk#1774 |
|
OK, 6.0.6 is now releases. Please rebase. |
…TIONS JS library code can already mutate the compile-time EXPORTED_FUNCTIONS set at library load time, which under MODULARIZE=instance causes jsifier to emit the symbol with an `export` declaration. This makes that flow fully work by forwarding the final EXPORTED_FUNCTIONS set back from the JS compiler so the linker can derive which JS library symbols were exported, and have the WASM_ESM_INTEGRATION wrapper re-export them. This is used by binding layers (e.g. wasm-bindgen) that define a public JS API surface distinct from the wasm export names, registering it from their generated JS library.
bc3d67c to
ab22aee
Compare
|
Ok the Changelog entry is now updated to 6.0.7. |
ab22aee to
d1fb203
Compare
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
The `__force`/`__export` JS library decorators that the generated library_bindgen.js relies on landed in emscripten 6.0.7 (emscripten-core/emscripten#27436); on older versions they are silently misparsed as symbol names and initBindgen is dropped. 6.0.7 also fixes the rustc prebuilt-std Wasm EH linking that previously forced the 6.0.5 pin (emscripten-core/emscripten#27496).
wasm-bindgen (wasm-bindgen/wasm-bindgen#5210, updated for the __export/ __force symbol attributes from emscripten-core#27436 in wasm-bindgen/wasm-bindgen#5253) hoists the clean exported API (functions, classes, enums) into top-level library symbols that self-register as exports via its `--js-library`. The user-facing API now comes from wasm-bindgen's library in every flow, so emscripten no longer needs to guess or own the export set. This collapses the previous staticlib-only handling into a single -sWASM_BINDGEN path that works whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies -sEXPORTED_FUNCTIONS) or emcc drives it (staticlib, exports discovered locally): - The exports the wasm-bindgen expansion reaches by name - the supplied EXPORTED_FUNCTIONS (method shims, the __wbindgen_* runtime, the marker, main) plus anything its expansion adds - are internal glue, not a user API. They are captured and kept off every export layer: the ESM wrapper (user_requested_exports), the factory Module attachment (EXPORTED_FUNCTIONS, via should_export), and the keepalive pass in finalize_wasm. `main` still runs automatically on init; `_main` isn't surfaced. - A genuine EMSCRIPTEN_KEEPALIVE C/C++ export is not in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. Human-supplied EXPORTED_FUNCTIONS are not preserved through wasm-bindgen linkage yet (the rustc-supplied set is indistinguishable from glue); that can be revisited later. - Strip the placeholder symbols wasm-bindgen consumes (__wbindgen_describe*, __externref_*, ...) so they aren't reported as undefined exports. - Only run nm-based export discovery for explicit -sWASM_BINDGEN when no driver supplied EXPORTED_FUNCTIONS; the rustc-driven link already lists them exactly. - Wire imported JS: feed library_bindgen.extern-pre.js as extern-pre-js and copy the snippets/ dir next to the output so relative imports resolve. - The WASM_ESM_INTEGRATION wrapper re-exports the JS library symbols that were exported (MODULARIZE=instance), and provides wasmExports via a namespace import of the wasm so by-name export access works. Add -sWASM_BINDGEN=auto: run wasm-bindgen only when the linked wasm carries wasm-bindgen's __wasm_bindgen_emscripten_marker custom section, which is how cargo/rustc opts in when driving emcc as the linker (addressing the request to replace implicit marker detection with an explicit flag); otherwise it is a no-op and wasm-bindgen need not be installed. Both output modes then expose only the clean API (e.g. a `Greeter` class). Add an end-to-end test parameterized over the ESM and factory output modes (built via cargo with -sWASM_BINDGEN=auto), a no-marker test asserting auto is a no-op for an ordinary build, extend the staticlib integration test to assert an EMSCRIPTEN_KEEPALIVE export survives alongside the wasm-bindgen API, and install a pinned wasm-bindgen-cli alongside rust in CI so the flow is always exercised. The wasm-bindgen library and CLI are pinned to the same wasm-bindgen main rev (the attribute support is not yet in a release); they must match exactly, and can move to a version pin once released.
…ction (#27208) This unifies wasm-bindgen output generation under a single `-sWASM_BINDGEN` path, building on the wasm-bindgen side change in wasm-bindgen/wasm-bindgen#5210. It supersedes #27179. Previously `-sWASM_BINDGEN` was effectively a staticlib-only flow where emcc had to discover and own the export set itself. With wasm-bindgen/wasm-bindgen#5210, wasm-bindgen hoists its clean exported API (functions, classes, enums) into top-level library symbols that self-register as public exports via the `__export`/`__force` symbol attributes (#27436, wasm-bindgen/wasm-bindgen#5253) in its `--js-library`. The user-facing API now comes from wasm-bindgen's own library in every flow, so emscripten no longer needs to guess or own exports — it just surfaces what wasm-bindgen registered. That lets one `-sWASM_BINDGEN` path serve both whether cargo/rustc drives the link (bin crate, emcc as the linker, rustc supplies `-sEXPORTED_FUNCTIONS`) or emcc drives it (staticlib, exports discovered locally). The model for a public export is the union across both systems: wasm-bindgen's self-registered API, plus emscripten's own `EMSCRIPTEN_KEEPALIVE` exports — minus wasm-bindgen's internal expansion glue, which must not spill into the public surface. What's implemented: * `-sWASM_BINDGEN` is a no-op unless the linker inputs carry wasm-bindgen's `__wasm_bindgen_emscripten_marker` custom section (emitted by the wasm-bindgen crate). The check runs on the inputs before the link (`llvm-objdump --section-headers`, so archive members are covered), so there is a single link and no speculative exports. When the marker is absent wasm-bindgen is never invoked and need not be installed, so cargo/rustc can pass the flag unconditionally via `-Clink-arg` without affecting ordinary builds. * The exports the wasm-bindgen expansion reaches by name — the supplied `EXPORTED_FUNCTIONS` (method shims, the `__wbindgen_*` runtime, the marker, `main`) plus anything its expansion adds — are captured as internal glue and kept off every export layer: the ESM wrapper (`user_requested_exports`), the factory `Module` attachment (`EXPORTED_FUNCTIONS`, via `should_export`), and the keepalive pass in `finalize_wasm`. `main` still runs automatically on init; `_main` isn't surfaced. * A genuine `EMSCRIPTEN_KEEPALIVE` C/C++ export is **not** in that internal set and remains surfaced, so a hand-written native export composes with wasm-bindgen's API in the same module. * Placeholder symbols wasm-bindgen consumes (`__wbindgen_describe*`, `__externref_*`, ...) are stripped so they aren't reported as undefined exports. * nm-based export discovery only runs when no driver supplied `EXPORTED_FUNCTIONS`; the rustc-driven link already lists them exactly. * Imported JS is wired through: `library_bindgen.extern-pre.js` is fed as extern-pre-js and the `snippets/` dir is copied next to the output so relative imports resolve. * Under `WASM_ESM_INTEGRATION`, `wasmExports` is provided via a namespace import of the wasm so wasm-bindgen's by-name export access works. This is gated behind `WASM_BINDGEN` so plain ESM integration keeps per-symbol named imports and their tree-shakability. (The wrapper re-export of self-registered JS library symbols itself landed in #27436.) Both output modes then expose only the clean API (e.g. a `Greeter` class). Testing: * End-to-end test parameterized over the ESM (`-sWASM_ESM_INTEGRATION`) and factory (`-sMODULARIZE -sEXPORT_ES6`) output modes, built via `cargo build` with `-sWASM_BINDGEN` passed as a link arg, asserting the clean `Greeter` API works, `main` runs on init, and none of the raw wasm exports leak. * A no-marker test asserting `-sWASM_BINDGEN` is a no-op for an ordinary `hello_world.c` build (doesn't require wasm-bindgen installed). * The staticlib integration test is extended to assert an `EMSCRIPTEN_KEEPALIVE` native export survives alongside the wasm-bindgen API (fails under a blanket export wipe). * CI installs a pinned `wasm-bindgen-cli` alongside rust so the flow is always exercised. Not in scope (follow-up): preserving human-supplied `EXPORTED_FUNCTIONS` through wasm-bindgen linkage (the rustc-supplied set is currently indistinguishable from glue, so explicit exports aren't surfaced).
This implements support for JS libraries declaring their own public exports using per-symbol attributes, split out from #27208 as requested in review there.
The attributes separate symbol inclusion from export visibility:
__export: trueexports the symbol if it is otherwise included.__force: trueincludes the symbol even when nothing references it, without exporting it, analogous toDEFAULT_LIBRARY_FUNCS_TO_INCLUDE.This allows binding layers such as wasm-bindgen to define a public JS API surface distinct from the wasm export names, including exported classes and namespaces:
The attributes are consumed as JS library compile-time metadata and do not appear in generated output. The JS compiler forwards only the symbols actually emitted through
extraExports, allowing theWASM_ESM_INTEGRATIONwrapper to re-export them without mutating or returning the globalEXPORTED_FUNCTIONSsetting. Decorated exports are also retained through meta-DCE.Test coverage verifies the independent attribute semantics under legacy modularized output,
MODULARIZE=instance,WASM_ESM_INTEGRATION, and optimized-O3builds, together with decorator validation.Made with AI assistance under my review